#include "vbb_USART.h"

VBB_USART * usarts[6];

void USART1_IRQHandler(void)
{	
	char c;		
	if (READ_BIT(USART1->SR, USART_SR_RXNE))
	{		
        c = USART1->DR;
        vbb_DataQueue_AddByte(&(usarts[1]->rBuffer), c);
	}
}

void USART3_IRQHandler(void)
{	
	char c;		
	if (READ_BIT(USART3->SR, USART_SR_RXNE))
	{		
        c = USART3->DR;
        vbb_DataQueue_AddByte(&(usarts[3]->rBuffer), c);        
	}
}

void USART2_IRQHandler(void)
{	
	char c;		
	if (READ_BIT(USART2->SR, USART_SR_RXNE))
	{		
        c = USART2->DR;
        vbb_DataQueue_AddByte(&(usarts[2]->rBuffer), c);
	}
}

void UART5_IRQHandler(void)
{
    int c;
    if (READ_BIT(UART5->SR, USART_SR_RXNE))
	{		                
        c = UART5->DR & 0x1FF;        
        vbb_DataQueue_AddByte(&(usarts[5]->rBuffer), c);
        
	}
}

void UART4_IRQHandler(void)
{
    int c;
    if (READ_BIT(UART4->SR, USART_SR_RXNE))
    {        
        c = UART4->DR & 0x1FF;        
        vbb_DataQueue_AddByte(&(usarts[4]->rBuffer), c);
    }
}

void vbb_USART_Init(VBB_USART * Usart, USART_TypeDef * USARTx, unsigned int BaudRate, unsigned int PriorityRate, char * Buffer, unsigned int BufferSize)
{
    if (USARTx == USART1) //console
    {        
        vbb_OUTPUT_Deinit();
        
        vbb_PIN_Init(&(Usart->pin_tx), GPIOA, 9, PIN_MODE_ALTERNATE_OUTPUT_PUSH_PULL);
        vbb_PIN_Init(&(Usart->pin_rx), GPIOA, 10, PIN_MODE_FLOATING_INPUT);        
        
        RCC->APB2ENR |=  RCC_APB2ENR_USART1EN; // Enabled USART1 Clock
        USART1->CR1   = USART_CR1_RE | USART_CR1_TE | USART_CR1_RXNEIE; // Enable RX, TX, RXNEIE
        USART1->CR2   &= ~(USART_CR2_STOP); // One Stop Bit
        USART1->CR3   = 0x0000; // No Hardware Flow Control
        USART1->BRR = 72000000 / BaudRate;        
        vbb_DelayMillis(100);
        USART1->CR1 |= USART_CR1_UE;                
        
        NVIC_SetPriority(USART1_IRQn, PriorityRate);
        NVIC_EnableIRQ(USART1_IRQn);
        
        Usart->USARTx = USART1;
        usarts[1] = Usart;
    }    
    else if (USARTx == USART2)
    {
        vbb_PIN_Init(&(Usart->pin_tx), GPIOA, 2, PIN_MODE_ALTERNATE_OUTPUT_PUSH_PULL);
        vbb_PIN_Init(&(Usart->pin_rx), GPIOA, 3, PIN_MODE_FLOATING_INPUT);        
        
        RCC->APB1ENR |=  RCC_APB1ENR_USART2EN;
        USART2->CR1   = USART_CR1_RE | USART_CR1_TE | USART_CR1_RXNEIE; // Enable RX, TX, RXNEIE
        USART2->CR2   &= ~(USART_CR2_STOP); // One Stop Bit
        USART2->CR3   = 0x0000; // No Hardware Flow Control
        USART2->BRR = 72000000 / BaudRate;        
        vbb_DelayMillis(100);
        USART2->CR1 |= USART_CR1_UE;                
        
        NVIC_SetPriority(USART2_IRQn, PriorityRate);
        NVIC_EnableIRQ(USART2_IRQn);
        
        Usart->USARTx = USART2;
        usarts[2] = Usart;
    }
    else if (USARTx == USART3) //gps
    {
        vbb_PIN_Init(&(Usart->pin_tx), GPIOB, 10, PIN_MODE_ALTERNATE_OUTPUT_PUSH_PULL);
        vbb_PIN_Init(&(Usart->pin_rx), GPIOB, 11, PIN_MODE_FLOATING_INPUT);        
        
        RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
        USART3->CR1   = USART_CR1_RE | USART_CR1_TE | USART_CR1_RXNEIE; // Enable RX, TX, RXNEIE
        USART3->CR2   &= ~(USART_CR2_STOP); // One Stop Bit
        USART3->CR3   = 0x0000; // No Hardware Flow Control
        USART3->BRR = 72000000 / BaudRate;        
        vbb_DelayMillis(100);
        USART3->CR1 |= USART_CR1_UE;                
        
        NVIC_SetPriority(USART3_IRQn, PriorityRate);
        NVIC_EnableIRQ(USART3_IRQn);
        
        Usart->USARTx = USART3;
        usarts[3] = Usart;
    }    
    else if (USARTx == UART4)
    {
        vbb_PIN_Init(&(Usart->pin_tx), GPIOC, 10, PIN_MODE_ALTERNATE_OUTPUT_PUSH_PULL);
        vbb_PIN_Init(&(Usart->pin_rx), GPIOC, 11, PIN_MODE_FLOATING_INPUT);        
        
        RCC->APB1ENR &= ~RCC_AHBENR_SDIOEN;
        RCC->APB1ENR |=  RCC_APB1ENR_UART4EN;
        UART4->CR1   = USART_CR1_RE | USART_CR1_TE | USART_CR1_RXNEIE; // Enable RX, TX, RXNEIE
        UART4->CR2   &= ~(USART_CR2_STOP); // One Stop Bit
        UART4->CR3   = 0x0000; // No Hardware Flow Control
        UART4->BRR = 72000000 / BaudRate;        
        
        vbb_DelayMillis(100);
        UART4->CR1 |= USART_CR1_UE;                
        
        NVIC_SetPriority(UART4_IRQn, PriorityRate);
        NVIC_EnableIRQ(UART4_IRQn);
        
        Usart->USARTx = UART4;
        usarts[4] = Usart;
    }
    else if (USARTx == UART5) //gsm
    {
        vbb_PIN_Init(&(Usart->pin_tx), GPIOC, 12, PIN_MODE_ALTERNATE_OUTPUT_PUSH_PULL);
        vbb_PIN_Init(&(Usart->pin_rx), GPIOD, 2, PIN_MODE_FLOATING_INPUT);        
        
        RCC->APB1ENR &= ~RCC_AHBENR_SDIOEN;
        RCC->APB1ENR |=  RCC_APB1ENR_UART5EN;
        UART5->CR1   = USART_CR1_RE | USART_CR1_TE | USART_CR1_RXNEIE; // Enable RX, TX, RXNEIE
        UART5->CR2   &= ~(USART_CR2_STOP); // One Stop Bit
        UART5->CR3   = 0x0000; // No Hardware Flow Control
        UART5->BRR = 72000000 / BaudRate;        
        
        vbb_DelayMillis(100);
        UART5->CR1 |= USART_CR1_UE;                
        
        NVIC_SetPriority(UART5_IRQn, PriorityRate);
        NVIC_EnableIRQ(UART5_IRQn);
        
        Usart->USARTx = UART5;
        usarts[5] = Usart;
    }
    
    vbb_DataQueue_Init(&(Usart->rBuffer), Buffer, BufferSize);
}

void vbb_USART_WriteByte(VBB_USART * Usart, char Byte)
{
    while (!READ_BIT(Usart->USARTx->SR, USART_SR_TXE))
    {
    }
    CLEAR_BIT(Usart->USARTx->SR, USART_SR_TXE);
    Usart->USARTx->DR = Byte;
    while (!READ_BIT(Usart->USARTx->SR, USART_SR_TXE))
    {
    }
}

void vbb_USART_Print(VBB_USART * Usart, const char * Text)
{
    while (Text[0] != 0)
    {
        vbb_USART_WriteByte(Usart, Text[0]);
        Text++;
    }
}

void vbb_USART_ClearBuffer(VBB_USART * Usart)
{
    Usart->rBuffer.head = Usart->rBuffer.tail = 0;
}
